#!/usr/bin/env python
import inspect
import traceback

import six

from squirrel_core.commons.utils.logger import Logging
from squirrel_core.commons.utils.tools import walk_modules

__all__ = ["get_procedure_classes", "get_procedure", "DefaultProcedure"]


def get_procedure_classes(paths=None):
    module_paths = []
    module_paths.append(__package__)
    if isinstance(paths, (list, tuple)):
        module_paths.extend(paths)
    elif isinstance(paths, (str,)):
        module_paths.append(paths)
    exceptions = []
    for path in module_paths:
        for _module in walk_modules(path):
            try:
                _module = inspect.importlib.reload(_module)
                for obj in six.itervalues(vars(_module)):
                    if inspect.isclass(obj) and issubclass(obj, (DefaultProcedure,)):
                        yield obj
            except Exception as err:
                exceptions.append(err)


def get_procedure(procedure_type, *args, **kwargs):
    logger = Logging()
    procedure = None
    try:
        classes = get_procedure_classes()
        mapping = {}
        for _class in classes:
            try:
                procedure_name = getattr(_class, "procedure_name")
                procedure_name = procedure_name.fget(None)
                if procedure_name:
                    mapping.update({
                        procedure_name: _class
                    })
            except Exception:
                err_msg = traceback.format_exc()
                logger.info(f"data procedure {_class} don't have a valid procedure name, error:\r\n{err_msg}")

        if procedure_type in mapping.keys():
            procedure = mapping[procedure_type](logger, *args, **kwargs)
    except Exception:
        err_msg = traceback.format_exc()
        logger.info(f"failed to get data procedure {procedure_type}, error:\r\n{err_msg}")

    if not procedure:
        procedure = DefaultProcedure(logger, *args, **kwargs)

    return procedure


class DefaultProcedure(object):
    def __init__(self, logger, *args, **kwargs):
        self.logger = logger

    @property
    def procedure_name(self):
        """
        return data procedure specific name, sub class should always implement this
        Returns:
            string value
        """
        return "default"

    def process_item(self, item_dict, *args, **kwargs):
        """
        process payload data before db save it
        Args:
            item_dict: payload data
            *args:
            **kwargs:

        Returns:
            None
        """
        pass

    def fill_suffix_q_name(self, item_dict, *args, **kwargs):
        try:
            queue_suffix = item_dict['_suffix']
            item_dict.pop("_suffix")
        except KeyError:
                queue_suffix = ''
        if "name_second" in item_dict:
            item_dict['name_second'] = item_dict.get('name_second', "") + queue_suffix
